package cn.ant.utils;

import cn.ant.entity.AopControllerLogEntity;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Map;

/**
 * @Version 1.0
 * @Author:lss
 * @Date:2021/10/28
 * @Content:
 */
@Slf4j
@Aspect
@Component
@Scope("prototype")
public class AopControllerLog {
    //开始时间
    private Long startTime;
    //访问的类
    private Class clazz;
    //访问的方法
    private Method method;
    //格式化时间
    String strDateFormat = "yyyy-MM-dd HH:mm:ss";
    SimpleDateFormat dateFormat = new SimpleDateFormat(strDateFormat);

    /**
     * 声明切点
     */
    @Pointcut("@within(cn.ant.annotation.AopControllerLog)")//类生效
    private void aspect(){}

    @Around(value = "aspect()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around.start");
        long startTime = System.currentTimeMillis();
        //获取出参
        Object proceed = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        //获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        StringBuffer requestURL = request.getRequestURL();
        String ip = request.getRemoteAddr();
        String requestMethodName = request.getMethod();//请求方法
        Map<String, String[]> parameterMap = request.getParameterMap();
        //切人点的方法
        String pointCutMethodName = proceedingJoinPoint.getSignature().getName();
        //切人点方法出参类型
        String declaringTypeName = proceedingJoinPoint.getSignature().getDeclaringTypeName();
        //切人点方法入参
        Object[] args = proceedingJoinPoint.getArgs();
        //装配
        AopControllerLogEntity aopControllerLogEntity = new AopControllerLogEntity();
        aopControllerLogEntity.setIp(ip);
        aopControllerLogEntity.setUrl(requestURL.toString());
        aopControllerLogEntity.setDeclaringTypeName(declaringTypeName);
        aopControllerLogEntity.setArgs(args);
        aopControllerLogEntity.setParameterMap(parameterMap);
        aopControllerLogEntity.setRequestMethodName(requestMethodName);
        aopControllerLogEntity.setPointCutMethodName(pointCutMethodName);
        aopControllerLogEntity.setTimeConsuming(endTime-startTime);
        aopControllerLogEntity.setResponse(proceed);
        log.info("aopControllerLogEntity ===========> {}", JSONUtil.toJsonStr(aopControllerLogEntity));
        log.info("around.end");
        return proceed;
    }

    @AfterThrowing(value = "aspect()",throwing = "e")
    public void afterThrowing(JoinPoint joinPoint,RuntimeException e){
        long startTime = System.currentTimeMillis();
        //获取出参
        long endTime = System.currentTimeMillis();
        //获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        StringBuffer requestURL = request.getRequestURL();
        String ip = request.getRemoteAddr();
        String requestMethodName = request.getMethod();//请求方法
        Map<String, String[]> parameterMap = request.getParameterMap();
        //切人点的方法
        String pointCutMethodName = joinPoint.getSignature().getName();
        //切人点方法出参类型
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        //切人点方法入参
        Object[] args = joinPoint.getArgs();
        //装配
        AopControllerLogEntity aopControllerLogEntity = new AopControllerLogEntity();
        aopControllerLogEntity.setIp(ip);
        aopControllerLogEntity.setUrl(requestURL.toString());
        aopControllerLogEntity.setDeclaringTypeName(declaringTypeName);
        aopControllerLogEntity.setArgs(args);
        aopControllerLogEntity.setParameterMap(parameterMap);
        aopControllerLogEntity.setRequestMethodName(requestMethodName);
        aopControllerLogEntity.setPointCutMethodName(pointCutMethodName);
        aopControllerLogEntity.setTimeConsuming(endTime-startTime);
        aopControllerLogEntity.setErrorMessage(e.getMessage());
        log.info("afterThrowing_aopControllerLogEntity {}",aopControllerLogEntity);
    }
}
